/*************************************************************************
        > File Name: operator.h
        > Author: xuwenlong
        > Mail: myxuan475@126.com
        > Created Time: 2018年02月06日 星期二 12时42分09秒
 ************************************************************************/
#ifndef __OPERATOR_H__
#define __OPERATOR_H__

#include "cmdvalue.h"
#include "data.h"
#include "opitem.h"
#include "opvalue.h"
#include <functional>
#include <map>
#include <stack>
#include <stdio.h>
#include <string>
#include <utils/logger.h>
#include <vector>

namespace libxcom {

class Operator {
public:
    Operator(OpInterface *opInterface);

    virtual ~Operator();

    OpInterface *Interface();
    void SetInterface(OpInterface *iface);
    OpValue operator[](const std::string &var);
    void SetVar(const std::string &var, const OpValue &v);
    void clearOut();

    void RegisterFunction(
        const std::string &fname, std::function<OpValue(const std::string &, int32_t, const CmdValue &)> func);

    /*
     * 命令生产
     */
    int32_t InsertCmd(int index, const OpValue &value);
    OpValue GetCmd(int32_t start = 0, int32_t length = -1);
    int32_t GetLength();
    /* 必须按顺序添加参数 */
    void AddParam(OpValue value);
    OpValue GetParam(int32_t index);

    /* 相关计算 */
    std::shared_ptr<Express> FindDefinition(const std::string &def);
    OpValue VarCall(const char *var, int32_t pos = 0, const CmdValue &cmdValue = CmdValue::Null());
    OpValue FunctionCall(const char *func, int32_t pos = 0, const CmdValue &recvCmd = CmdValue::Null());

    OpValue EncodeCalc(const char *func, const CmdValue &recvCmd);

    OpValue CmdCalc(const char *func, OpValue &data);

    OpValue KeyFunctionCall(const char *keyfunc, int32_t byte = 0, const CmdValue &cmdValue = CmdValue::Null());
    OpValue BaseCall(const char c, OpValue &v1, OpValue &v2);
    OpValue SingleCall(const char c, OpValue &v);
    TYPE_DEFINE VarType(const char *var);
    TYPE_DEFINE FuncType(const char *func);
    TYPE_DEFINE CalcType(const char *func);

private:
    class OperatorData {
    public:
        OperatorData() {}
        std::vector<OpValue> opResult;
    };
    OperatorData &topData();

    class OperatorParam {
    public:
        OperatorParam() {}
        std::vector<OpValue> opParams;
    };
    OperatorParam &topParam();

    OpValue opDitch_;

public:
    enum { AUTO_CMD = 0, AUTO_PARAM };
    class AutoOperator {
    public:
        /* mode:0直接入栈，1延迟入栈 */
        AutoOperator(Operator &op, uint32_t type, uint32_t mode = 0) :
            opData(op), stacktype(type), stackmode(mode), push(mode == 0)
        {
            if (mode == 0)
                opData.PushStack(stacktype);
        }

        void AddList(const OpValue &value)
        {
            templist.push_back(value);
        }

        int32_t StackAll()
        {
            opData.PushStack(stacktype);
            opData.AddtoStack(stacktype, templist);
            push = true;
            return 0;
        }

        virtual ~AutoOperator()
        {
            if (push)
                opData.PopStack(stacktype);
        }

    private:
        Operator &opData;
        bool push;
        uint32_t stacktype;
        uint32_t stackmode;
        std::vector<OpValue> templist;
    };

    void PushStack(uint32_t type);
    void PopStack(uint32_t type);
    void AddtoStack(uint32_t type, const std::vector<OpValue> &list);

private:
    OpInterface *opInterface_;
    std::map<std::string, OpValue> mapOut_;
    std::stack<OperatorData> stackData_;
    std::stack<OperatorParam> stackParam_;
    std::map<std::string, std::function<OpValue(const std::string &, int32_t, const CmdValue &)>> mapFuncs_;
};
} // namespace libxcom
#endif //__OPERATOR_H__
